﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Sinacor.OMM.Configuration.HFTMessageManager;
using Sinacor.OMM.Configuration.Router;
using System.Configuration;
using System.IO;
using Sinacor.OMM.Configuration;
using Sinacor.OMM.Configuration.OrderBovespaSystem;
using System.Threading;
using System.Management;
using System.Diagnostics;
using Sinacor.OMM.Logging;
using PSE.Framework.Threading;

namespace Sinacor.OMM.Router.ProcessLogic
{
    /// <summary>
    /// Manage the router process configuration
    /// </summary>
    public class RouterConfigurationManager
    {
        static string _configFile;
        static RouterConfiguration _configurationInstance;
        static AuthenticationConfiguration _authentication;
        static OrderBovespaSystemConfiguration _orderBovespaSystemInformation;
        private static bool _shouldStopRefreshing = false;
        public static event ProcessEntity.RouterEventHandler OnError;        
        private static object _authenticationLock = new object();
        private static Mutex _mutex = new Mutex();

        /// <summary>
        /// Starts refreshing the configuration.
        /// </summary>
        public static void StartRefresh()
        {
            _shouldStopRefreshing = false;
            Thread messageReaderThread = new Thread(new ThreadStart(UpdateConfiguration));
            messageReaderThread.Start();
        }

        /// <summary>
        /// Stops refreshing the configuration.
        /// </summary>
        public static void StopRefresh()
        {
            _shouldStopRefreshing = true;
        }

        /// <summary>
        /// Update the configuration
        /// </summary>
        private static void UpdateConfiguration()
        {
            while (!_shouldStopRefreshing)
            {
                Sleeper.Sleep(60000, () => !_shouldStopRefreshing);

                try
                {
                    BuildOrderBovespaSystemInformation();
                }
                catch (Exception ex)
                {
                    if (OnError != null)
                        OnError(null, new Sinacor.OMM.Router.ProcessEntity.RouterEventArgs()
                        {
                            ErrorMessage = string.Concat(ex.Message, " ", ex.StackTrace),
                            ShouldPause = false
                        });
                }
            }
        }

        /// <summary>
        /// Authentication configuration
        /// </summary>
        public static AuthenticationConfiguration Authentication
        {
            get
            {
                try
                {
                    lock (_authenticationLock)
                    {
                        if (_authentication == null)
                        {
                            Int32 companyId;

                            _authentication = new AuthenticationConfiguration();
                            System.Configuration.Configuration config = GetExeConfiguration();

                            if (config == null)
                                throw new ConfigurationErrorsException(string.Format("Arquivo de configuração '{0}'.config não encontrado.", _configFile));

                            if (!Int32.TryParse(config.AppSettings.Settings["companyId"].Value, out companyId))
                                throw new ConfigurationErrorsException(String.Format("Código da empresa não encontrado, impossível realizar a conexão com o banco de dados do Sinacor." + System.Environment.NewLine +
                                                                                     "Verificar a tag appSettings do arquivo {0}.config. Verificar a existência da chave  <add key='companyId' value='' />.", _configFile));

                            _authentication.CompanyId = companyId;

                            if (config.AppSettings.Settings["user"] != null)
                                _authentication.User = config.AppSettings.Settings["user"].Value;

                            if (config.AppSettings.Settings["password"] != null)
                                _authentication.Password = config.AppSettings.Settings["password"].Value;
                        }
                    }
                }
                catch (Exception ex)
                {
                    EventLog.WriteEntry("Router Service Configuration", ex.ToString(), EventLogEntryType.Error);
                    throw ex;
                }

                return _authentication;
            }
        }

        private static System.Configuration.Configuration GetExeConfiguration()
        {
            if (string.IsNullOrEmpty(_configFile))
                _configFile = Path.Combine(Path.GetDirectoryName(System.Configuration.ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None).FilePath), "Sinacor.OMM.Router.exe");

            System.Configuration.Configuration config = ConfigurationManager.OpenExeConfiguration(_configFile);
            return config;
        }        

        /// <summary>
        /// Order Bovespa System Information
        /// </summary>
        public static OrderBovespaSystemConfiguration OrderBovespaSystemInformation
        {
            get
            {
                try
                {
                    if (_orderBovespaSystemInformation == null)
                        BuildOrderBovespaSystemInformation();

                }
                catch (Exception ex)
                {
                    EventLog.WriteEntry(LogSources.RouterService, string.Concat(ex.Message, " ", ex.StackTrace), EventLogEntryType.Error);
                }

                return _orderBovespaSystemInformation;
            }
        }

        /// <summary>
        /// Router configuration
        /// </summary>
        public static RouterConfiguration RouterConfiguration
        {
            get
            {
                try
                {
                    if (_configurationInstance == null)
                        BuildRouterConfiguration();
                }
                catch (Exception ex)
                {
                    EventLog.WriteEntry("Router Service Configuration", ex.ToString(), EventLogEntryType.Error);
                    throw ex;
                }

                return _configurationInstance;
            }
        }

        /// <summary>
        /// Build router configuration
        /// </summary>
        private static void BuildRouterConfiguration()
        {
            _configurationInstance = new OMM.Configuration.Router.RouterConfigurationReader(Authentication.CompanyId).GetConfiguration();

            if (_configurationInstance == null)
                throw new ConfigurationErrorsException("Configurações do Roteador não cadastradas.Verificar a tabela TBOCNFG_ROTR.");

            _configurationInstance.MacAddress = GetMacAddress();
        }

        /// <summary>
        /// Build order Bovespa system information
        /// </summary>
        private static void BuildOrderBovespaSystemInformation()
        {
            _mutex.WaitOne();

            if (_orderBovespaSystemInformation == null)
                _orderBovespaSystemInformation = new OrderBovespaSystemConfiguration();

            _mutex.ReleaseMutex();

            lock (_orderBovespaSystemInformation)
            {
                _orderBovespaSystemInformation =
                   new OrderBovespaSystemConfigurationReader(Authentication.CompanyId).GetOrderBovespaSystemInformation();
            }            
        }

        /// <summary>
        /// Get de mac address of machine where the HFT process is installed
        /// </summary>
        /// <returns></returns>
        private static string GetMacAddress()
        {
            ManagementClass management = new ManagementClass("Win32_NetworkAdapterConfiguration");
            ManagementObjectCollection managementObjects = management.GetInstances();
            string macAddress = string.Empty;

            foreach (ManagementObject item in managementObjects)
            {
                if ((bool)item["IPEnabled"] == true)
                {
                    macAddress = item["MacAddress"].ToString().Replace(":", "").Trim();
                }

                item.Dispose();
            }

            management.Dispose();
            managementObjects.Dispose();

            return macAddress;
        }

    }
}
